package com.atguigu.spzx.user.service.Impl;


import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil;
import com.atguigu.spzx.model.dto.api.ApiUserLoginDTO;
import com.atguigu.spzx.model.dto.api.ApiUserRegisterDTO;
import com.atguigu.spzx.model.entity.user.UserInfo;
import com.atguigu.spzx.model.exception.GuiguException;
import com.atguigu.spzx.model.vo.common.ResultCodeEnum;
import com.atguigu.spzx.model.vo.user.UserInfoVo;
import com.atguigu.spzx.tools.SpzxConsts;
import com.atguigu.spzx.user.mapper.UserInfoMapper;
import com.atguigu.spzx.user.service.UserInfoService;
import com.atguigu.spzx.util.IpUtil;
import com.atguigu.spzx.util.RegexValidateUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author LT
 * @create 2024-03-27-16:35
 */
@Service
public class UserInfoServiceImpl extends ServiceImpl<UserInfoMapper,UserInfo> implements UserInfoService {


    @Resource
    RedisTemplate redisTemplate;

    @Lazy
    @Resource
    UserInfoService userInfoService;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Override
    public void register(ApiUserRegisterDTO userRegisterDTO) {
        //1.校验参数
        String username = userRegisterDTO.getUsername(); //phone
        String password = userRegisterDTO.getPassword();
        String nickName = userRegisterDTO.getNickName();
        String code = userRegisterDTO.getCode();
        if (StringUtils.isEmpty(username)
            ||!RegexValidateUtils.checkCellphone(username)
            || StringUtils.isEmpty(password)
            || StringUtils.isEmpty(nickName)
            || StringUtils.isEmpty(code)){
            throw new GuiguException(ResultCodeEnum.REDISTER_PARAMS_ERROR);
        }
        //2.校验验证码
        String dbcode = stringRedisTemplate.opsForValue().get("spzx:sms:code" + username);
        if (!StringUtils.equals(code,dbcode)){
            throw new GuiguException(ResultCodeEnum.VALIDATE_COOE_ERROR);
        }
        //3.用户是否已注册
        Long count = this.count(Wrappers.lambdaQuery(UserInfo.class).eq(UserInfo::getUsername, username));
        if (count > 0){
            throw new GuiguException(ResultCodeEnum.MOBILE_EXISTS_ERROR);
        }
        //4.密码加密（加盐）
        String salt = RandomUtil.randomString(6);
        String dbPassword = DigestUtils.md5DigestAsHex((DigestUtils.md5DigestAsHex(password.getBytes()) + salt).getBytes());
        //5.保存数据
        UserInfo userInfo = new UserInfo();
        userInfo.setNickName(nickName);
        userInfo.setUsername(username);
        userInfo.setPassword(dbPassword);
        userInfo.setAvatar("http://192.168.184.129:8848/nacos/img/logo-2000-390.svg");
        userInfo.setSex(1);
        userInfo.setPhone(username);
        userInfo.setStatus(1);
        userInfo.setSalt(salt);
        baseMapper.insert(userInfo);
    }

    @Override
    public String login(ApiUserLoginDTO userLoginDTO) {

        //1.校验参数
        String username = userLoginDTO.getUsername();
        String password = userLoginDTO.getPassword();
        if (StringUtils.isEmpty(username)||
        !RegexValidateUtils.checkCellphone(username)
        ||StringUtils.isEmpty(password)){
            throw new GuiguException(ResultCodeEnum.LOGIN_PARAMS_ERROR);
        }
        //2.根据账号查询数据库用户信息
        UserInfo userInfo = baseMapper.selectOne(Wrappers.lambdaQuery(UserInfo.class)
                .eq(UserInfo::getUsername, username));
        if (ObjectUtils.isEmpty(userInfo)){
            throw new GuiguException(ResultCodeEnum.LOGIN_USERNAME_ERROR);
        }
        //3.密码加盐加密和数据库密文比较
        String dbPwd = userInfo.getPassword();
        String encodePwd = DigestUtils.md5DigestAsHex((DigestUtils.md5DigestAsHex(password.getBytes()) + userInfo.getSalt()).getBytes());
        if (!dbPwd.equals(encodePwd)){
            throw new GuiguException(ResultCodeEnum.LOGIN_PASSWORD_ERROR);
        }
        //4、更新最后一次登录的时间和ip地址
        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        String ipAddress = IpUtil.getIpAddress(requestAttributes.getRequest());
        userInfo.setLastLoginIp(ipAddress);
        userInfo.setLastLoginTime(new Date());
        //5.保存登录状态：保存到redis中
        String token = IdUtil.getSnowflake(1,1).nextIdStr();
        //数据脱敏
        userInfo.setPassword(null);
        userInfo.setOpenId(null);

        userInfoService.updateLoginInfo(userInfo);

        redisTemplate.opsForValue().set(SpzxConsts.SPZX_USER_LOGIN_PREFIX+token,userInfo,3, TimeUnit.DAYS);
        return token;
    }

    @Async
    @Override
    public void updateLoginInfo(UserInfo userInfo) {

        this.update(Wrappers.lambdaUpdate(UserInfo.class)
                .set(UserInfo::getLastLoginIp,userInfo.getLastLoginIp())
                .set(UserInfo::getLastLoginTime,userInfo.getLastLoginTime())
                .set(UserInfo::getUpdateTime,userInfo.getUpdateTime())
                .eq(UserInfo::getId,userInfo.getId()));


    }

    @Override
    public UserInfoVo getCurrentUserInfo(String token) {
        UserInfo userInfo = (UserInfo) redisTemplate.opsForValue().get(SpzxConsts.SPZX_USER_LOGIN_PREFIX + token);
        UserInfoVo userInfoVo = new UserInfoVo();
        userInfoVo.setNickName(userInfo.getNickName());
        userInfoVo.setAvatar(userInfo.getAvatar());
        return userInfoVo;
    }

    @Override
    public void logout(String token) {
        redisTemplate.delete(SpzxConsts.SPZX_USER_LOGIN_PREFIX+token);
    }
}
